package com.kgc.scd.resolver;

import com.alibaba.fastjson.JSON;
import com.kgc.scd.annotation.RequestUser;
import com.kgc.scd.util.RedisUtils;
import com.kgc.scd.util.UserAnno;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * @program: com.kgc.springcloud.resolver
 * @author: HarryXzy
 * @create: 2022-06-01 11:27
 * @description: 自定义请求用户信息解析器，根据@RequestUser注解，将鉴权通过的用户信息自动绑定到请求处理方法的参数上
 **/
@Slf4j
public class RequestUserResolver implements HandlerMethodArgumentResolver {
    @Autowired
    private RedisUtils redisUtils;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 确定支持参数解析的注解和目标类型,要求：目标请求处理方法的形参必须是有指定的注解@RequestUser,且注解需要被解析的目标类型必须是User
        return parameter.hasParameterAnnotation(RequestUser.class) && parameter.getParameterType().isAssignableFrom(UserAnno.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        // 上面的方法supportsParameter返回了true，代表需要进行目标方法的参数解析，如果返回了false，不需要解析，此方法不执行
        // 从redis中获取token参数对应的用户详情信息，转换为目标对象（前提：请求需要权限校验是否通过）
        Object userObj = redisUtils.get(webRequest.getHeader("token"));
        log.info("++++ 鉴权通过，执行请求用户信息解析 ++++");
        // 将解析后的目标实体对象，自动传递到目标请求处理方法的形参上（@RequestUser注释指定的参数），目标请求处理方法
        return JSON.parseObject(userObj.toString(), UserAnno.class);
    }
}
